package com.noovo.comport.server;

import android.content.ContentValues;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import java.io.IOException;
import java.security.InvalidParameterException;

import com.noovo.comport.serial.SerialBean;
import com.noovo.comport.serial.SerialHelper;

public class ComHandler {
	private SerialHelper sHelper;
	private String sPort;
	private int iBaudRate = 0;
	private volatile int port;
	private volatile String name;
	private static Handler serviceHandler;
	private int connect_time = 0;
	public volatile int store_loop = -1;
	private int iDatabits = 8;
	private int iStopbits = 1;
	private char iParity = 'n';
	private byte[] combinByte;

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	// public void setBaudRate(int baudRate) {
	// iBaudRate = baudRate;
	// }

	public ComHandler(int port, Handler serviceHandler) {
		this.port = port;
		this.serviceHandler = serviceHandler;
	}

	public void onClose() {
		if (sHelper != null && sHelper.isOpen()) {
			Log.d(ComInfo.TAG, "Try to close port=" + port + " sPort=" + sPort);
			sHelper.setLoopStatus(false);
			sHelper.close();
		}
	}

	public void onOpen(int baudrate, int databits, int stopbits, char parity) {
		connect_time = 0;
		serviceHandler.removeMessages(ComInfo.HANDLER_SERVICE_ERROR);
		sPort = ComInfo.getPort(port);
		if (TextUtils.isEmpty(sPort)) {
			Log.d(ComInfo.TAG, "Open Fail: Can not find the port=" + port + " sPort is null");
			return;
		} else {
			Log.d(ComInfo.TAG, "Try to open port=" + port + " sPort=" + sPort);
		}

		parity = Character.toLowerCase(parity);
		if (iBaudRate != baudrate || iDatabits != databits || iStopbits != stopbits || iParity != parity) {
			iBaudRate = baudrate;
			iDatabits = databits;
			iStopbits = stopbits;
			iParity = parity;
			initAndOpenSerial();
		}
	}

	public void initAndOpenSerial() {
		Log.d(ComInfo.TAG, "initAndOpenSerial port=" + port + " sPort=" + sPort);
		if (sHelper != null && sHelper.isOpen())
			sHelper.close();
		if (sHelper == null) {
			sHelper = new SerialHelper(sPort, iBaudRate) {

				@Override
				protected void onDataReceived(SerialBean bean) {
					bean.setPort(port);
					Message m = new Message();
					m.what = ComInfo.HANDLER_SERVICE_COM_DATA_RECEIVE;
					m.obj = bean;
					serviceHandler.sendMessage(m);
					serviceHandler.removeMessages(port);
					serviceHandler.sendEmptyMessageDelayed(port, getDataFinishTime());
				}

				@Override
				protected void onDataSend(byte[] data) {
				}
			};
		}
		sHelper.setBaudRate(iBaudRate);
		sHelper.setOpt(iDatabits, iStopbits, iParity);

		try {
			sHelper.open();
		} catch (SecurityException e) {
			Log.e(ComInfo.TAG, "open " + sPort + " serial fial: no read/write permission");
		} catch (IOException e) {
			Log.e(ComInfo.TAG, "open " + sPort + " serial fial, unknown error");
			errorConnect();
		} catch (InvalidParameterException e) {
			Log.e(ComInfo.TAG, "open " + sPort + " serial fial, parameter error");
			errorConnect();
		}
	}

	public void onDataReceive(byte[] newByte) {
		if (combinByte == null) {
			int size = newByte.length;
			combinByte = new byte[size];
			for (int i = 0; i < size; i++) {
				combinByte[i] = newByte[i];
			}
		} else {
			int oldSize = combinByte.length;
			int newSize = newByte.length;
			byte[] combin = new byte[oldSize + newSize];
			for (int i = 0; i < oldSize; i++) {
				combin[i] = combinByte[i];
			}
			for (int i = 0; i < newSize; i++) {
				combin[oldSize + i] = newByte[i];
			}
			combinByte = combin;
		}
	}

	public void finishDataReceive() {
		ContentValues values = new ContentValues();
		values.put(ComInfo.DB_ITEM_PORT, port);
		values.put(ComInfo.DB_ITEM_RECEIVE, combinByte);
		values.put(ComInfo.DB_ITEM_NAME, name);
		values.put(ComInfo.DB_ITEM_RECEIVE_ID, getStoreLoopNumber());
		Message m = new Message();
		m.what = ComInfo.HANDLER_SERVICE_RECEIVE;
		m.obj = values;
		serviceHandler.sendMessage(m);
		combinByte = null;
	}

	public int getDataFinishTime() {
		if (port == 4) {
			return getDataFinishTimeBoard();
		}
		switch (iBaudRate) {
		case 9600:
			return 100;
		case 115200:
			return 100;
		default:
			return 100;
		}
	}

	public int getDataFinishTimeBoard() {
		switch (iBaudRate) {
		case 9600:
			return 100;
		case 115200:
			return 60;
		default:
			return 100;
		}
	}

	private void errorConnect() {
		if (connect_time <= ComInfo.CONNECT_TRY_MAX) {
			Message m = new Message();
			m.what = ComInfo.HANDLER_SERVICE_ERROR;
			m.obj = port;
			serviceHandler.removeMessages(ComInfo.HANDLER_SERVICE_ERROR);
			serviceHandler.sendMessageDelayed(m, ComInfo.CONNECT_TRY_DELSY);
			connect_time++;
		}
	}

	public void onSendMessage(byte[] msg, boolean loop, int iDelay) {
		if (msg == null || sHelper == null)
			return;
		sHelper.setbLoopData(msg);
		sHelper.setLoopStatus(loop);
		if (loop) {
			sHelper.setiDelay(iDelay);
		}
		Log.d(ComInfo.TAG, sPort + " now start send msg");
		sHelper.startSend();
	}

	public void onStopMessage() {
		if (sHelper != null) {
			sHelper.setLoopStatus(false);
		}
	}

	private int getStoreLoopNumber() {
		store_loop++;
		if (store_loop == ComInfo.DB_ITEM_RECEIVE_MAX) {
			store_loop = 0;
		}
		return store_loop;
	}
}
